package service

import (
	"fly/global"
	"fly/helper"
	"fly/models"
	"fly/req"
	"fly/resp"
	"fly/schema"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/duke-git/lancet/v2/condition"
	"github.com/duke-git/lancet/v2/convertor"
	"github.com/duke-git/lancet/v2/slice"
	"net/url"
	"time"
)

const (
	FlightTaskCacheAircraftKey     = "BizConfigCacheKey:%d"
	FlightTaskListCacheAircraftKey = "FlightTaskListCacheAircraftKey:%d"
)

type FlightTaskService struct {
	BaseService
	SysDictService           SysDictService
	AircraftComponentService AircraftComponentService
}

func (c *FlightTaskService) GetPaginateData(params url.Values) ([]*models.FlightTask, Pagination) {
	c.WhereField = append(c.WhereField, new(models.FlightTask).WhereField()...)
	var data []*models.FlightTask
	var aircraftList []*models.Aircraft
	if aircraftCode := params.Get("aircraftCode"); len(aircraftCode) > 0 {
		_, _ = orm.NewOrm().QueryTable(new(models.Aircraft)).Filter("code", aircraftCode).Filter("status__gte",
			schema.Enabled).All(&aircraftList, "id")
		if len(aircraftList) == 0 {
			return data, c.Pagination
		}
	}
	o := orm.NewOrm().QueryTable(new(models.FlightTask))
	_, err := c.PaginateAndScopeWhere(o, params, func(cond *orm.Condition) *orm.Condition {
		if len(aircraftList) > 0 {
			ids := slice.Map(aircraftList, func(index int, item *models.Aircraft) int64 {
				return item.Id
			})
			cond = cond.And("aircraft_id__in", ids)
		}
		startTime := params.Get("startTime")
		endTime := params.Get("endTime")
		if len(startTime) > 0 && len(endTime) > 0 {
			start, err1 := convertor.ToInt(startTime)
			end, err2 := convertor.ToInt(endTime)
			if err1 == nil && err2 == nil {
				cond = cond.And("create_time__gte", helper.Milli2ChinaStr(start)).And("create_time__lte",
					helper.Milli2ChinaStr(end))
			}
		}
		cond = condition.TernaryOperator(params.Has("sceneId"), cond.And("task_scene_id", params.Get("sceneId")), cond)
		return cond
	}).All(&data)
	if err != nil {
		return nil, c.Pagination
	}
	return data, c.Pagination
}

// GetIdsByDeptId 根据部门下的飞机ids
func (c *FlightTaskService) GetIdsByDeptId(deptId int64) []int64 {
	var list []*models.FlightTask
	qs := orm.NewOrm().QueryTable(new(models.FlightTask)).Filter("dept_id", deptId)
	_, err := qs.All(&list, "id")
	if err != nil {
		return nil
	}
	ids := slice.Map(list, func(index int, item *models.FlightTask) int64 {
		return item.Id
	})
	return ids
}

// GetTaskByAircraftId 根据飞机id查询飞机任务
func (c *FlightTaskService) GetTaskByAircraftId(aircraftId int64) (*models.FlightTask, error) {
	key := fmt.Sprintf(FlightTaskCacheAircraftKey, aircraftId)
	return global.GetCache[*models.FlightTask](key, func() (*models.FlightTask, error) {
		task := models.FlightTask{}
		err := orm.NewOrm().QueryTable(new(models.FlightTask)).Filter("aircraft_id", aircraftId).Filter("status__gte", schema.Enabled).One(&task)
		return &task, err
	})
}

// GetWaitTasksByAircraftId 根据飞机id查询飞机待执行的任务
func (c *FlightTaskService) GetWaitTasksByAircraftId(aircraftId int64) ([]*models.FlightTask, error) {
	key := fmt.Sprintf(FlightTaskListCacheAircraftKey, aircraftId)
	return global.GetCache[[]*models.FlightTask](key, func() ([]*models.FlightTask, error) {
		var tasks []*models.FlightTask
		_, err := orm.NewOrm().QueryTable(new(models.FlightTask)).Filter("aircraft_id", aircraftId).Filter("status",
			schema.Enabled).All(&tasks)
		return tasks, err
	})
}

func (c *FlightTaskService) GetTaskById(id int64) (*models.FlightTask, error) {
	task := models.FlightTask{}
	err := orm.NewOrm().QueryTable(new(models.FlightTask)).Filter("id", id).One(&task)
	return &task, err
}

func (c *FlightTaskService) FinishTask(params *req.FlightTaskStatusReq, task *models.FlightTask, uid int64) (err error) {
	if params == nil || task == nil {
		return fmt.Errorf("params is nil")
	}
	task.Status = params.Status
	task.ActualUpDownCount += params.ActualUpDownCount
	task.ActualDuration += params.ActualDuration
	if task.Status == schema.FlightTaskFinish {
		// 已完成，飞机累加实际值
		aircraft, _ := models.GetAircraftById(task.AircraftId)
		if aircraft != nil {
			aircraft.FlightDuration += task.ActualDuration
			aircraft.TotalUpDown += task.ActualUpDownCount
			aircraft.LatestFlightTime = helper.TimePoint(time.Now())
			_, _ = orm.NewOrm().Update(aircraft, "flight_duration", "total_up_down", "latest_flight_time")
			// 添加配件工作时间
			_ = c.AircraftComponentService.AddComponentDuration(aircraft.Id, task, params.ComponentSaveReq, uid)
		}
		// 飞行经历累加
		experience := models.AircraftExperience{}
		err = orm.NewOrm().QueryTable(new(models.AircraftExperience)).Filter("aircraft_id",
			task.AircraftId).Filter("experience_dict_id", task.TaskSceneId).One(&experience)
		if err == nil {
			experience.Count += 1
			_, _ = orm.NewOrm().Update(&experience, "count")
		}
	}
	return models.UpdateFlightTaskById(task, uid)
}

// RecommendAircraft 推荐执行飞机
func (c *FlightTaskService) RecommendAircraft(params []*req.FlightTaskRecommendReq) ([]*resp.RecommendAircraftResp, error) {
	if params == nil {
		return nil, fmt.Errorf("params is nil")
	}
	// 1. 先筛选可用的飞机
	var aircraftList []*models.Aircraft
	o := orm.NewOrm()
	normalState, err := c.SysDictService.GetDictByCodeKey("aircraft_state", "normal")
	qs := o.QueryTable(new(models.Aircraft)).Filter("status", schema.AircraftIdle).Filter("enabled__gte", schema.Enabled)
	if normalState != nil {
		qs = qs.Filter("state_dict_id", normalState.Id)
	}
	count, err := qs.All(&aircraftList)
	if err != nil || count == 0 {
		return nil, err
	}
	list := make([]*resp.RecommendAircraftResp, len(params))
	for i, param := range params {
		// 根据任务经历来排序处理
		var experiences []*models.AircraftExperience
		_, _ = o.QueryTable(new(models.AircraftExperience)).Filter("experience_dict_id",
			param.TaskSceneId).OrderBy("-count").All(&experiences, "aircraft_id")
		var idNames []*resp.IdName
		for _, experience := range experiences {
			aircraft, _ := slice.FindBy(aircraftList, func(index int, item *models.Aircraft) bool {
				return item.Id == experience.AircraftId
			})
			if aircraft != nil {
				name, _ := c.SysDictService.GetDictValueById(aircraft.TypeDictId)
				idNames = append(idNames, &resp.IdName{
					Id:   experience.AircraftId,
					Name: name,
					Code: aircraft.Code,
				})
			}
		}
		if len(idNames) == 0 {
			// 没有匹配的，取全部的
			idNames = slice.Map(aircraftList, func(index int, item *models.Aircraft) *resp.IdName {
				name, _ := c.SysDictService.GetDictValueById(item.Id)
				return &resp.IdName{
					Id:   item.Id,
					Name: name,
					Code: item.Code,
				}
			})
		}
		list[i] = &resp.RecommendAircraftResp{
			TaskCode: param.TaskCode,
			List:     idNames,
		}
	}
	return list, nil
}

func (c *FlightTaskService) UpdateAllTaskStatus() (err error) {
	var list []*models.FlightTask
	o := orm.NewOrm()
	// 所有默认待执行的任务，查询是否已失效
	_, err = o.QueryTable(new(models.FlightTask)).Filter("status", schema.Enabled).All(&list)
	if err != nil || len(list) == 0 {
		return err
	}
	for _, task := range list {
		if task.PlanStart != nil && time.Now().After(task.PlanStart.Add(30*time.Minute)) {
			// 任务已失效
			task.Status = schema.FlightTaskInvalid
			_, err = o.Update(task, "status")
			if err != nil {
				return err
			}
		}
	}
	return nil
}
